package cn.itcast.nems.studentrecord.service.impl.studentrecord;

import cn.itcast.ic.common.exception.v2.BizExceptionProducer;
import cn.itcast.ic.common.exception.v2.bean.BizStatusEnum;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.studentrecord.constant.ReferenceTypeEnum;
import cn.itcast.nems.studentrecord.converter.StudentRecordTransactionConverter;
import cn.itcast.nems.studentrecord.dao.entity.StudentRecordTransaction;
import cn.itcast.nems.studentrecord.dao.mapper.StudentRecordTransactionMapper;
import cn.itcast.nems.studentrecord.dto.change.StudentRecordTransactionChangeCheckDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordTransactionCreateDTO;
import cn.itcast.nems.studentrecord.dto.studentrecord.StudentRecordTransactionDTO;
import cn.itcast.nems.studentrecord.enumeration.StudentRecordTransactionStateEnum;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordTransactionService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 学籍流转明细;“物流”：只记录有出入班的操作 服务实现类
 * </p>
 *
 * @author liyong
 * @since 2023-11-14
 */
@Service
@Slf4j
@AllArgsConstructor
public class StudentRecordTransactionServiceImpl implements StudentRecordTransactionService {

    private final StudentRecordTransactionMapper studentRecordTransactionMapper;

    @Override
    public void chargeAgainstInClazz(StudentRecordTransactionCreateDTO createDto) {
        final String srId = createDto.getStudentRecordId();
        final StudentRecordTransaction lastTransaction = this.studentRecordTransactionMapper.selectLastTransaction(srId, StudentRecordTransaction.TYPE_IN);
        if (lastTransaction == null) {
            log.warn("学籍'{}' 没有找到流转记录，忽略其改期计划", srId);
            return;
        }
        final StudentRecordTransaction chargeAgainst = StudentRecordTransactionConverter.convertChargeAgainst(lastTransaction);
        chargeAgainst.setReferenceType(createDto.getReferenceType().name());
        chargeAgainst.setReferenceId(createDto.getReferenceId());
        chargeAgainst.setReferenceLineId(createDto.getReferenceLineId());
        final LocalDateTime now = LocalDateTime.now();
        chargeAgainst.setCreatedDatetime(now);
        this.studentRecordTransactionMapper.insert(chargeAgainst);

        StudentRecordTransaction newTransaction = new StudentRecordTransaction();
        BeanUtils.copyProperties(createDto, newTransaction);
        newTransaction.setReferenceType(createDto.getReferenceType().toString());
        final StudentRecordTransactionStateEnum stateEnum = createDto.getState();
        String state = stateEnum != null ? stateEnum.name() : StudentRecordTransactionStateEnum.VALID.name();
        newTransaction.setState(state);
        newTransaction.setCreatedDatetime(now.plusSeconds(1));
        this.studentRecordTransactionMapper.insert(newTransaction);
    }

    @Override
    public List<StudentRecordTransactionChangeCheckDTO> findStudentRecordTransactionChangeChecks(int studentId) {
        final List<StudentRecordTransaction> transactions = this.studentRecordTransactionMapper.selectStudentRecordTransactions(studentId);
        if (transactions == null || transactions.isEmpty()) {
            return Collections.emptyList();
        }
        return transactions
                .stream()
                .map(t -> {
                    StudentRecordTransactionChangeCheckDTO dto = new StudentRecordTransactionChangeCheckDTO();
                    BeanUtils.copyProperties(t, dto);
                    return dto;
                }).collect(Collectors.toList());
    }

    @Override
    public StudentRecordTransactionDTO findLastStudentRecordTransactionDTO(String studentRecordId,
                                                                           ReferenceTypeEnum referenceType) {
        final StudentRecordTransaction transaction = this.studentRecordTransactionMapper.selectLastByStudentRecordReference(studentRecordId, referenceType.toString());
        StudentRecordTransactionDTO dto = new StudentRecordTransactionDTO();
        BeanUtils.copyProperties(transaction, dto);
        return dto;
    }

    @Override
    public boolean exist(String referenceId, String referenceLineId, int clazzId, int studentId) {
        final List<StudentRecordTransaction> ts = this.studentRecordTransactionMapper
                .selectByReferenceClazzIdStudentId(referenceId, referenceLineId, clazzId, studentId);
        return ts != null && !ts.isEmpty();
    }

    @Override
    public boolean createStudentRecordTransaction(StudentRecordTransactionCreateDTO dto) {
        final StudentRecordTransaction old = this.studentRecordTransactionMapper.selectByStudentRecordReference(dto.getStudentRecordId(),
                dto.getReferenceType().name(),
                dto.getReferenceId(),
                dto.getReferenceLineId());
        if (old != null) {
            log.warn("学籍'{}' 凭单/订单(类型：'{}' 行ID：'{}')对应的流转记录已经存在", dto.getStudentRecordId(), dto.getReferenceType(), dto.getReferenceLineId());
            return false;
        }
        StudentRecordTransaction transaction = new StudentRecordTransaction();
        BeanUtils.copyProperties(dto, transaction);
        transaction.setReferenceType(dto.getReferenceType().toString());
        final StudentRecordTransactionStateEnum stateEnum = dto.getState();
        String state = stateEnum != null ? stateEnum.name() : StudentRecordTransactionStateEnum.VALID.name();
        transaction.setState(state);
        this.check(transaction);
        this.studentRecordTransactionMapper.insert(transaction);
        return true;
    }

    @Override
    public void updateState(ReferenceTypeEnum referenceType, String referenceLineId, String studentRecordId, StudentRecordTransactionStateEnum state) {
        String modifiedBy = AccountHolder.getRequiredAccountInfo().getEmail();
        this.studentRecordTransactionMapper.updateState(referenceType.toString(), referenceLineId, studentRecordId, modifiedBy, state.toString());
    }

    @Override
    public StudentRecordTransaction selectLastLeaveByStudentRecordId(String studentRecordId) {
        return this.studentRecordTransactionMapper.selectLastLeaveByStudentRecordId(studentRecordId);
    }

    private void check(StudentRecordTransaction transaction) {
        final StudentRecordTransaction last = this.studentRecordTransactionMapper.selectLastByStudentRecordId(transaction.getStudentRecordId(), StudentRecordTransactionStateEnum.VALID.toString());
        if (last != null && last.getType().intValue() == transaction.getType().intValue()) {
            BizExceptionProducer.throwServerError(BizStatusEnum.BAD_REQUEST.toString(), "学籍ID '%s' 最近一条有效流转记录同为: %s"
                    , transaction.getStudentRecordId()
                    , transaction.getType().intValue() == StudentRecordTransaction.TYPE_IN ? "转入" : "转出");
        }
    }
}
